/**
 * 
 */

IXPathResult = new function(){
	this.ANY_TYPE = 0;
	this.NUMBER_TYPE = 1;
	this.STRING_TYPE = 2;
	this.BOOLEAN_TYPE = 3;
	this.UNORDERED_NODE_ITERATOR_TYPE = 4;
	this.ORDERED_NODE_ITERATOR_TYPE = 5;
	this.UNORDERED_NODE_SNAPSHOT_TYPE = 6;
	this.ORDERED_NODE_SNAPSHOT_TYPE = 7;
	this.ANY_UNORDERED_NODE_TYPE = 8;
	this.FIRST_ORDERED_NODE_TYPE = 9;
};

Node = new function(){
	this.ELEMENT_NODE = 1;
	this.ATTRIBUTE_NODE = 2;
	this.TEXT_NODE = 3;
	this.CDATA_SECTION_NODE = 4;
	this.ENTITY_REFERENCE_NODE = 5;
	this.ENTITY_NODE = 6;
	this.PROCESSING_INSTRUCTION_NODE = 7;
	this.COMMENT_NODE = 8;
	this.DOCUMENT_NODE = 9;
	this.DOCUMENT_TYPE_NODE = 10;
	this.DOCUMENT_FRAGMENT_NODE = 11;
	this.NOTATION_NODE = 12;
};

function XMLParser() {
	if (navigator.appName == "Microsoft Internet Explorer") {
		this.newDocument = function() {
			var xmlDOM;
			var progIDs = [ 'Msxml2.DOMDocument.6.0', 'Msxml2.DOMDocument.4.0' ];
			for ( var i = 0; i < progIDs.length; i++) {
				try {
					xmlDOM = new ActiveXObject(progIDs[i]);
					if (undefined != xmlDOM && xmlDOM != null) {
						xmlDOM.resolveExternals = true;
						if (progIDs[i] == 'Msxml2.DOMDocument.6.0')
							xmlDOM.setProperty("ProhibitDTD", false);
						return xmlDOM;
					}
				} catch (ex) {
				}
			}
		}

		this.parseFromString = function(xmlString) {
			var document = this.newDocument();
			document.validateOnParse = false;
			document.loadXML(xmlString);
			return document;
		}
	} else {
		this.newDocument = function() {
			return document.implementation.createDocument("", "", null);
		}

		this.parseFromString = function(xmlString) {
			var parser = new DOMParser();
			return parser.parseFromString(xmlString, "text/xml");
		}
	}
}

function XSLTransformer() {
	if (navigator.appName == "Microsoft Internet Explorer") {
		var progIDs = [ 'Msxml2.XSLTemplate.6.0', 'Msxml2.XSLTemplate.4.0' ];
		for ( var i = 0; i < progIDs.length; i++) {
			try {
				this._template = new ActiveXObject(progIDs[i]);
				if (undefined != this._template && this._template != null)
					break;
			} catch (ex) {
			}
		}
		this._processor = null;

		this.setStylesheetUrl = function(url) {
			var xslDoc;
			var progIDs = [ 'MSXML2.FreeThreadedDOMDocument.6.0',
					'MSXML2.FreeThreadedDOMDocument.4.0' ];
			for ( var i = 0; i < progIDs.length; i++) {
				try {
					xslDoc = new ActiveXObject(progIDs[i]);
					if (undefined != xslDoc && xslDoc != null) {
						xslDoc.resolveExternals = true;
						xslDoc.setProperty("AllowXsltScript", true);
						xslDoc.setProperty("AllowDocumentFunction", true);
						break;
					}
				} catch (ex) {
				}
			}

			xslDoc.async = false;
			xslDoc.load(url);
			this._template.stylesheet = xslDoc;
			this._processor = this._template.createProcessor();
		}

		this.setStylesheetString = function(xslString) {
			var xslDoc;
			var progIDs = [ 'MSXML2.FreeThreadedDOMDocument.6.0',
					'MSXML2.FreeThreadedDOMDocument.4.0' ];
			for ( var i = 0; i < progIDs.length; i++) {
				try {
					xslDoc = new ActiveXObject(progIDs[i]);
					if (undefined != xslDoc && xslDoc != null) {
						xslDoc.resolveExternals = true;
						xslDoc.setProperty("AllowXsltScript", true);
						break;
					}
				} catch (ex) {
				}
			}

			xslDoc.async = false;
			xslDoc.loadXML(xslString);
			this._template.stylesheet = xslDoc;
			this._processor = this._template.createProcessor();
		}

		this.setParameter = function(name, value) {
			var processor = this._getProcessor();
			if (name.indexOf("object::") == 0) {
				var namespaceUri = name.substring("object::".length);
				processor.addObject(value, namespaceUri);
			} else {
				processor.addParameter(name, value);
			}
		}

		this.clearParameters = function() {
			this._processor = null; // this._template.createProcessor();
		}

		this.reset = function() {
			this._processor = null; // this._template.createProcessor();
		}

		this._getProcessor = function() {
			if (this._processor == null) {
				this._processor = this._template.createProcessor();
			}
			return this._processor;
		}

		this.transform = function(source, output) {
			var processor = this._getProcessor();
			processor.input = source;
			if (output != undefined) {
				processor.output = output;
			}
			var retval = processor.transform();
			var output = processor.output;
			processor.reset();
			return output;
		}
	} else {
		this._processor = null;

		this.setStylesheetUrl = function(url) {
			this._processor = new XSLTProcessor();
			var xslDoc = document.implementation.createDocument("", "", null);
			var loadFn = loadStylesheet(this._processor, xslDoc);
			xslDoc.addEventListener("load", loadFn, false);
			bol = xslDoc.load(url);
		}

		function loadStylesheet(xslProcessor, xslDoc) {
			var loadFunction = function() {
				xslProcessor.importStylesheet(xslDoc)
			};
			return loadFunction;
		}

		this.setStylesheetString = function(xslString) {
			this._processor = new XSLTProcessor();
			var parser = new DOMParser();
			var xslDoc = parser.parseFromString(xslString, "text/xml");
			this._processor.importStylesheet(xslDoc);
		}

		this.setParameter = function(name, value) {
			this._processor.setParameter("", name, value);
		}

		this.clearParameters = function() {
			this._processor.clearParameters();
		}

		this.reset = function() {
			this._processor.reset();
		}

		this.transform = function(source, output) {
			if (!output) {
				var doc = this._processor.transformToDocument(source);
				var ser = new XMLDOMSerializer();
				return ser.serializeToString(doc);
			} else {
				var fragment = this._processor.transformToFragment(source,
						output);
				output.appendChild(fragment);
				return output;
			}
		}
	}
}

function XMLDOMSerializer() {
	if (navigator.appName == "Microsoft Internet Explorer") {
		this.serializeToString = function(node) {
			return node.xml;
		}
	} else {
		this.serializer = new XMLSerializer();
		this.serializeToString = function(node) {
			return this.serializer.serializeToString(node);
		}
	}
}

function XPathExpression() {
	if (navigator.appName == "Microsoft Internet Explorer") {
		this.selectNodes = function(node, xPath) {
			return new XPathResult(IXPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
					node.selectNodes(xPath));
		}

		this.selectSingleNode = function(node, xPath) {
			return node.selectSingleNode(xPath);
		}

		this.evaluate = function(node, xPath, returnType) {
			var result = null;
			var type = returnType == undefined ? IXPathResult.ANY_TYPE
					: returnType;
			// if result is primitive type then it has to be implemented using
			// XSl
			if (type <= 3) {
				var resultText = this.evaluateValueExpression(node, xPath);
				switch (type) {
				case IXPathResult.BOOLEAN_TYPE:
					result = new XPathResult(type,
							(resultText.toLowerCase() == 'true'));
					break;
				case IXPathResult.NUMBER_TYPE:
					result = new XPathResult(type, parseFloat(resultText));
					break;
				default:
					result = new XPathResult(type, resultText);
					break;
				}
			} else if (type > 3 && type < 8) {
				result = selectNodes(node, xPath);
			} else {
				result = new XPathResult(IXPathResult.FIRST_ORDERED_NODE_TYPE,
						selectSingleNode(node, xPath));
			}
			return result;
		}

	} else {
		this.selectNodes = function(node, xPath) {
			var doc = node.ownerDocument == null ? node : node.ownerDocument;
			var nsResolver = getNSResolver(doc.documentElement);

			return new XPathResult(
					IXPathResult.ORDERED_NODE_SNAPSHOT_TYPE, doc.evaluate(xPath,
							node, nsResolver,
							IXPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null));
		}

		this.selectSingleNode = function(node, xPath) {
			var doc = node.ownerDocument == null ? node : node.ownerDocument;
			var nsResolver = null;// XMLObjectFactory.getXPathNSResolver(doc.documentElement);
			var resultset = doc.evaluate(xPath, node, nsResolver,
					IXPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
			var result = null;
			if (resultset.snapshotLength > 0) {
				result = resultset.snapshotItem(0);
			}
			return result;
		}

		this.evaluate = function(node, xPath, returnType) {
			var type = returnType == undefined ? IXPathResult.ANY_TYPE
					: returnType;
			var doc = node.ownerDocument == null ? node : node.ownerDocument;
			var nsResolver = null;
			var resultVal = null;
			var resultType = type;
			resultVal = doc.evaluate(xPath, node, nsResolver, type, null);
			resultType = resultVal.resultType;

			var value = resultVal;
			switch (resultType) {
			case IXPathResult.NUMBER_TYPE:
				value = resultVal.numberValue;
				break;
			case IXPathResult.STRING_TYPE:
				value = resultVal.stringValue;
				break;
			case IXPathResult.BOOLEAN_TYPE:
				value = resultVal.booleanValue;
				break;
			case IXPathResult.FIRST_ORDERED_NODE_TYPE:
			case IXPathResult.ANY_UNORDERED_NODE_TYPE:
				value = resultVal.singleNodeValue;
				break;
			}
			return new XPathResult(resultType, value);
		}
	}
}

function XPathResult(type, value) {
	if (navigator.appName == "Microsoft Internet Explorer") {
		this.index = 0;
		this.resultType = type;
		this.value = value;
		this.length = (type == IXPathResult.UNORDERED_NODE_SNAPSHOT_TYPE 
		               || type == IXPathResult.ORDERED_NODE_SNAPSHOT_TYPE ?
						  value.length : 0);
		this.item = function(index) {
			return this.value.item(index); 
		}
		
		this.nextNode = function() {
			return this.value.nextNode(); 
		}
		
		this.getValue = function() {
			return this.value;
		}
	} else {
		this.index = 0;
		this.value = value;
		this.length = (type == IXPathResult.UNORDERED_NODE_SNAPSHOT_TYPE 
		               || type == IXPathResult.ORDERED_NODE_SNAPSHOT_TYPE ?
						  value.snapshotLength : 0);	
		this.resultType = type;
		this.item = function(index) {
			return this.value.snapshotItem(index); 
		}
		
		this.nextNode = function() {
			var result = null;
			if (this.value.resultType == IXPathResult.UNORDERED_NODE_ITERATOR_TYPE
				|| this.value.resultType == IXPathResult.ORDERED_NODE_ITERATOR_TYPE) {
				result = this.value.iterateNext();
			}
			else if (this.index < this.length) {
				result = this.value.snapshotItem(this.index++); 
			}
			return result;
		}
		
		this.getValue = function() {
			return this.value;
		}
	}
}

function getNSResolver(node) {
	if (navigator.appName == "Netscape") {
		var resolver = null;
		if (node == null || node == undefined) {
			resolver = new MozillaXPathNSResolver();
		}
		else {
			var mzResolver = new XPathEvaluator().createNSResolver(node);
			resolver = new MozillaXPathNSResolver(mzResolver, node);
		}
		return resolver;
	}
}

function MozillaXPathNSResolver(xPathResolver, node)
{
	this.resolver = xPathResolver;
	this.node = node;
	this.lookupNamespaceURI =  lookupNamespaceURI;
	
	function lookupNamespaceURI(prefix) {
		var uri = this.resolver.lookupNamespaceURI(prefix);
		if(uri == null && this.node != null){
			uri = this.node.getAttribute('xmlns:' + prefix);
		}
		return uri == null ? SYSTEM_NAMESPACES[prefix] : uri;
	}
}